package top.zhangjianyong.blog.utils;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.HMac;
import cn.hutool.crypto.digest.HmacAlgorithm;
import lombok.extern.slf4j.Slf4j;
import java.util.Objects;

/**
 * 签名验证工具类
 * 用于生成和验证文件访问签名，实现防盗链功能
 *
 * @author zhangjianyong
 * @since 2024/12/19
 */
@Slf4j
public class SignatureUtil {

    /**
     * 签名密钥（建议配置在配置文件中）
     */
    private static final String SECRET_KEY = "blog_file_access_secret_key_2024";

    /**
     * 签名有效期（秒）
     */
    private static final int SIGNATURE_EXPIRE_SECONDS = 3600; // 1小时

    /**
     * 生成文件访问签名
     *
     * @param fileName  文件名
     * @param type      文件类型
     * @param timestamp 时间戳
     * @return 签名
     */
    public static String generateSignature(String fileName, Integer type, Long timestamp) {
        if (StrUtil.isBlank(fileName) || Objects.isNull(type) || Objects.isNull(timestamp)) {
            return null;
        }

        // 构建签名字符串
        String signString = String.format("%s_%d_%d", fileName, type, timestamp);

        // 使用HMAC-SHA256生成签名
        HMac hMac = new HMac(HmacAlgorithm.HmacSHA256, SECRET_KEY.getBytes());
        return hMac.digestHex(signString);
    }

    /**
     * 验证签名是否有效
     *
     * @param fileName  文件名
     * @param type      文件类型
     * @param timestamp 时间戳
     * @param signature 签名
     * @return 是否有效
     */
    public static boolean verifySignature(String fileName, Integer type, Long timestamp, String signature) {
        if (StrUtil.isBlank(fileName) || Objects.isNull(type) || Objects.isNull(timestamp) || StrUtil.isBlank(signature)) {
            return false;
        }

        // 检查时间戳是否过期
        if (isTimestampExpired(timestamp)) {
            log.warn("签名已过期: fileName={}, type={}, timestamp={}", fileName, type, timestamp);
            return false;
        }

        // 生成期望的签名
        String expectedSignature = generateSignature(fileName, type, timestamp);

        // 比较签名
        boolean isValid = StrUtil.equals(signature, expectedSignature);

        if (!isValid) {
            log.warn("签名验证失败: fileName={}, type={}, signature={}", fileName, type, signature);
        }

        return isValid;
    }

    /**
     * 检查时间戳是否过期
     *
     * @param timestamp 时间戳
     * @return 是否过期
     */
    private static boolean isTimestampExpired(Long timestamp) {
        if (Objects.isNull(timestamp)) {
            return true;
        }

        long currentTime = System.currentTimeMillis() / 1000;
        return (currentTime - timestamp) > SIGNATURE_EXPIRE_SECONDS;
    }


} 